# aem.two_d.single.well --
#
# Copyright (c) 2000, V.Kelson and M.Bakker

from types import *
from cmath import log,pi

import geometry
XY = geometry.XY
XYZ = geometry.XYZ

import base

import aem.container
RowList = aem.container.RowList
ColumnList = aem.container.ColumnList
TraceCheck = aem.container.TraceCheck

class Well(geometry.two_d.Circle,base.Element):
	'''Class for wells

	Python call: Well(xc,yc,radius,Q=0.0,parent=None)

	Attributes:

	  - xc,yc: location of well (inherited from Circle)
	  - radius: radius of well (inherited from Circle)
	  - parent: parent of the element (inherited from Element)
	  - parameters: ColumnList of strength parameters, set to Q
	  - solver: solver (inherited from Element)
	  - elementList: list of elements, defaults to itself (inherited from Element)
	  - __numberOfParameters: number of parameters, set to 1

	Overloaded functions from Element: __init__, potentialInfluence, dischargeInfluence
	'''

	def __init__(self,xc=0.0,yc=0.0,radius=0.0,Q=0.0,parent=None):
		'''Constructor'''
		geometry.two_d.Circle.__init__(self,xc,yc,radius)
		base.Element.__init__(self,parent)
		self.__numberOfParameters = 1
		self.parameters = ColumnList([ Q ])

	def __repr__(self):
		# Parent not yet included
		return 'Well' + str((self.center.x,self.center.y,self.radius,self.parameters[0]))

	def __complexPotentialInfluence(self,xy):
		if self.isInArea(xy):
			return log(self.radius)/(2.0*pi)
		else:
			return log(complex(xy) - self.zc)/(2.0*pi)

	def potentialInfluence(self,xy,t=0):
		assert isinstance(xy,XY),"XY point is required"
		return RowList([(self.__complexPotentialInfluence(xy)).real])

	def __complexDischargeInfluence(self,xy):
		if self.isInArea(xy):
			return 0.0
		else:
			return -1./((complex(xy) - self.zc)*2.0*pi)

	def dischargeInfluence(self,xy,t=0):
		assert isinstance(xy,XY),"XY point is required"
		comdis = self.__complexDischargeInfluence(xy)
		return RowList([XY(comdis.real,-comdis.imag)])

	def nearElement(self,xyz1,xyz2,step):
		xy1 = xyz1.XY()
		xy2 = xyz2.XY()
		rv = TraceCheck()
		# If point 1 within step of well and discharge of well positive, then
		# terminate trace at well
		if self.distance2(xy1) < step and self.parameters[0] > 0:
			rv.change = 1
			rv.stop = 1
			rv.xyzchanged = XYZ(self.center.x,self.center.y,xyz1.z)
		return rv
